package com.fansl.koala.quickdev.module.users.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fansl.koala.quickdev.common.bean.PageBean;
import com.fansl.koala.quickdev.common.constants.CommonConstants;
import com.fansl.koala.quickdev.common.enums.DeleteFlagEnum;
import com.fansl.koala.quickdev.common.enums.MenuTypeEnum;
import com.fansl.koala.quickdev.common.enums.UserPermissionType;
import com.fansl.koala.quickdev.common.utils.TreeUtil;
import com.fansl.koala.quickdev.module.users.bean.dto.CustomUserPermissionDTO;
import com.fansl.koala.quickdev.module.users.entity.SysMenu;
import com.fansl.koala.quickdev.module.users.entity.SysRoleMenu;
import com.fansl.koala.quickdev.module.users.entity.SysUser;
import com.fansl.koala.quickdev.module.users.entity.SysUserMenu;
import com.fansl.koala.quickdev.module.users.mapper.SysMenuMapper;
import com.fansl.koala.quickdev.module.users.service.ISysMenuService;
import com.fansl.koala.quickdev.module.users.vo.SimpleTreeVo;
import com.fansl.koala.quickdev.module.users.vo.MenuTreeVo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 菜单权限表 服务实现类
 * </p>
 *
 * @author fansl
 * @since 2020-03-20
 */
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements ISysMenuService {
    @Resource
    private SysUserMenuServiceImpl sysUserMenuService;
    @Resource
    private SysRoleMenuServiceImpl sysRoleMenuService;

    /**
     * 分页查询菜单树形数据
     *
     * @param pageParam 分页参数
     * @param sysMenu   查询参数
     * @return 查询数据
     */
    @Override
    public PageBean<MenuTreeVo> pageTree(PageBean<MenuTreeVo> pageParam, SysMenu sysMenu) {
        //分页参数
        Page<SysMenu> queryPage = new Page<>();
        queryPage.setCurrent(pageParam.getPageNo());
        queryPage.setSize(pageParam.getPageSize());
        if (StrUtil.isNotBlank(pageParam.getSortOrder()) && StrUtil.isNotBlank(pageParam.getSortField())) {
            OrderItem orderItem = new OrderItem();
            orderItem.setAsc(pageParam.getSortOrder().equals(CommonConstants.PAGE_QUERY_ORDER_ASC));
            orderItem.setColumn(StrUtil.toUnderlineCase(pageParam.getSortField()));
            queryPage.setOrders(Collections.singletonList(orderItem));
        }
        //查询条件
        SysMenu queryParam = new SysMenu();
        if(StrUtil.isNotBlank(sysMenu.getName())){
            queryParam.setName(sysMenu.getName());
        }
        LambdaQueryWrapper<SysMenu> queryWrapper = Wrappers.lambdaQuery(queryParam);
        queryWrapper.eq(SysMenu::getParentId, CommonConstants.TREE_PARENT_TOP_ID)
                .eq(SysMenu::getDelFlag, DeleteFlagEnum.NOT_DELETE.getCode());

        Page<SysMenu> result = page(queryPage, queryWrapper);

        List<Integer> parentIds = result.getRecords().stream()
                .map(SysMenu::getMenuId).collect(Collectors.toList());
        List<SysMenu> subMenus = findAllAndSubDept(parentIds);
        subMenus.addAll(result.getRecords());
        //转换为树形结构
        List<MenuTreeVo> menuTreeList = getMenuTree(subMenus);
        pageParam.setData(menuTreeList);
        pageParam.setTotalCount(result.getTotal());
        pageParam.setTotalPage(result.getPages());
        return pageParam;
    }

    /**
     * 查询简单菜单树形列表
     *
     * @return 查询数据
     */
    @Override
    public List<SimpleTreeVo> listTree() {
        SysMenu query = new SysMenu();
        query.setDelFlag(DeleteFlagEnum.NOT_DELETE.getCode());
        List<SysMenu> sysMenuList = list(Wrappers.lambdaQuery(query));
        List<SimpleTreeVo> simpleTreeVos = sysMenuList.stream().map(sysMenu -> {
            SimpleTreeVo simpleTreeVo = new SimpleTreeVo();
            simpleTreeVo.setParentId(sysMenu.getParentId());
            simpleTreeVo.setId(sysMenu.getMenuId());
            simpleTreeVo.setTitle(sysMenu.getName());
            simpleTreeVo.setKey(sysMenu.getMenuId().toString());
            simpleTreeVo.setValue(sysMenu.getMenuId().toString());
            return simpleTreeVo;
        }).collect(Collectors.toList());
        SimpleTreeVo root = new SimpleTreeVo();
        root.setId(CommonConstants.TREE_PARENT_TOP_ID);
        root.setParentId(-1);
        root.setTitle("根目录");
        root.setKey(CommonConstants.TREE_PARENT_TOP_ID.toString());
        root.setValue(CommonConstants.TREE_PARENT_TOP_ID.toString());
        simpleTreeVos.add(root);
        return TreeUtil.buildByLoop(simpleTreeVos, -1);
    }

    /**
     * 获取所有权限
     *
     * @return 查询数据
     */
    @Override
    public List<SimpleTreeVo> listPermissions() {
        SysMenu query = new SysMenu();
        query.setDelFlag(DeleteFlagEnum.NOT_DELETE.getCode());
        List<SysMenu> sysMenuList = list(Wrappers.lambdaQuery(query));
        List<SimpleTreeVo> simpleTreeVos = sysMenuList.stream().map(sysMenu -> {
            SimpleTreeVo simpleTreeVo = new SimpleTreeVo();
            simpleTreeVo.setParentId(sysMenu.getParentId());
            simpleTreeVo.setId(sysMenu.getMenuId());
            simpleTreeVo.setTitle(sysMenu.getName());
            simpleTreeVo.setKey(sysMenu.getMenuId().toString());
            simpleTreeVo.setValue(sysMenu.getMenuId().toString());
            return simpleTreeVo;
        }).collect(Collectors.toList());
        return TreeUtil.buildByLoop(simpleTreeVos, CommonConstants.TREE_PARENT_TOP_ID);
    }

    /**
     * 获取用户自定义菜单ID
     *
     * @param userId 用户id
     * @param type   权限类型（1-加权限2-减权限）
     * @return 菜单ID
     */
    @Override
    public List<String> getUserMenuByType(Long userId, String type) {
        List<Integer> userMenuIds = sysUserMenuService.listMenusByType(userId, type);
        return userMenuIds.stream().map(menuId-> Integer.toString(menuId))
                .collect(Collectors.toList());
    }

    /**
     * 自定义用户自定义权限
     *
     * @param userId 用户id
     * @param param  自定义权限集合
     * @return TRUE/FALSE
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean customUserPermission(Long userId, CustomUserPermissionDTO param) {
        //移除原来的权限
        sysUserMenuService.remove(Wrappers.<SysUserMenu>lambdaQuery().eq(SysUserMenu::getUserId, userId));
        //新增现在的
        List<SysUserMenu> sysUserMenuList = new ArrayList<>();
        param.getAddPermissions().forEach(addMenuId -> {
            SysUserMenu sysUserMenu = new SysUserMenu();
            sysUserMenu.setMenuId(addMenuId);
            sysUserMenu.setUserId(userId.intValue());
            sysUserMenu.setType(UserPermissionType.ADD.getCode());
            sysUserMenuList.add(sysUserMenu);
        });
        param.getReducePermissions().forEach(reduceMenuId -> {
            SysUserMenu sysUserMenu = new SysUserMenu();
            sysUserMenu.setMenuId(reduceMenuId);
            sysUserMenu.setUserId(userId.intValue());
            sysUserMenu.setType(UserPermissionType.REDUCE.getCode());
            sysUserMenuList.add(sysUserMenu);
        });
        if (sysUserMenuList.isEmpty()) {
            return false;
        }
        return sysUserMenuService.saveBatch(sysUserMenuList);
    }

    /**
     * 获取角色自定义菜单ID
     *
     * @param roleId 角色id
     * @return 菜单ID
     */
    @Override
    public List<String> getRoleMenuByRoleId(Integer roleId) {
        List<SysRoleMenu> sysRoleMenus = sysRoleMenuService.list(Wrappers.<SysRoleMenu>lambdaQuery().eq(SysRoleMenu::getRoleId,roleId));
        return sysRoleMenus.stream().map(sysRoleMenu -> Integer.toString(sysRoleMenu.getMenuId()))
                .collect(Collectors.toList());
    }

    /**
     * 自定义角色权限
     *
     * @param roleId 角色id
     * @param param  自定义权限集合
     * @return TRUE/FALSE
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean customRolePermission(Integer roleId, Set<Integer> param) {
        //移除原角色的权限
        sysRoleMenuService.remove(Wrappers.<SysRoleMenu>lambdaQuery().eq(SysRoleMenu::getRoleId,roleId));
        //添加角色
        List<SysRoleMenu> sysRoleMenus = param.stream().map(menuId->{
            SysRoleMenu sysRoleMenu = new SysRoleMenu();
            sysRoleMenu.setMenuId(menuId);
            sysRoleMenu.setRoleId(roleId);
            return sysRoleMenu;
        }).collect(Collectors.toList());
       return sysRoleMenuService.saveBatch(sysRoleMenus);
    }

    /**
     * 查询当前菜单以及下级菜单信息
     *
     * @param menuIds
     * @return
     */
    public List<SysMenu> findAllAndSubDept(List<Integer> menuIds) {
        if (menuIds.isEmpty()) {
            return Collections.emptyList();
        }
        List<SysMenu> menuList = getBySubMenu(menuIds);

        List<Integer> subMenuIds = menuList.stream().map(SysMenu::getMenuId)
                .collect(Collectors.toList());
        if (subMenuIds.isEmpty()) {
            return menuList;
        }
        menuList.addAll(findAllAndSubDept(subMenuIds));
        return menuList;
    }

    public List<SysMenu> getBySubMenu(List<Integer> ids) {
        if (ids.isEmpty()) {
            return Collections.emptyList();
        }
        LambdaQueryWrapper<SysMenu> queryWrapper = Wrappers.<SysMenu>lambdaQuery()
                .in(SysMenu::getParentId, ids);
        return this.list(queryWrapper);
    }

    /**
     * 构建菜单树
     *
     * @param menuList 菜单列表
     * @return 菜单树形结构
     */
    private List<MenuTreeVo> getMenuTree(List<SysMenu> menuList) {
        List<MenuTreeVo> treeList = menuList.stream()
                .filter(menu -> !menu.getMenuId().equals(menu.getParentId()))
                .map(menu -> {
                    MenuTreeVo node = new MenuTreeVo();
                    node.setId(menu.getMenuId());
                    node.setParentId(menu.getParentId());
                    node.setName(menu.getName());
                    node.setPath(menu.getPath());
                    node.setPermission(menu.getPermission());
                    node.setLabel(menu.getName());
                    node.setComponent(menu.getComponent());
                    node.setIcon(menu.getIcon());
                    node.setKeepAlive(menu.getKeepAlive());
                    node.setSort(menu.getSort());
                    node.setType(MenuTypeEnum.findByCode(menu.getType()));
                    node.setCreateTime(menu.getCreateTime());
                    return node;
                }).collect(Collectors.toList());
        return TreeUtil.buildByLoop(treeList, CommonConstants.TREE_PARENT_TOP_ID);
    }
}
